package middleware

import (
	"fmt"
	"github.com/gin-gonic/gin"
	rotate "github.com/lestrrat-go/file-rotatelogs"
	"github.com/rifflock/lfshook"
	"github.com/sirupsen/logrus"
	"io"
	"os"
	"time"
)

func setOutPut(file *os.File, stdout bool) {
	if stdout {
		writers := []io.Writer{
			file,
			os.Stdout,
		}
		multiWriter := io.MultiWriter(writers...)
		logrus.SetOutput(multiWriter)
	} else {
		logrus.SetOutput(file)
	}
}

func Logger() gin.HandlerFunc {
	filePath := "log/log"
	//linkName := "latest_log.log"

	src, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
	if err != nil {
		fmt.Println("err", err)
	}
	logger := logrus.New()
	logrus.SetLevel(logrus.DebugLevel)
	logWriter, _ := rotate.New(
		filePath+"%Y%m%d.log",
		rotate.WithMaxAge(7*24*time.Hour),
		rotate.WithRotationTime(24*time.Hour),
		//rotate.WithLinkName(linkName),   // 创建软连接，以最新的日志文件创建软连接，以方便随着找到当前日志文件
	)

	writerMap := lfshook.WriterMap{
		logrus.InfoLevel:  logWriter,
		logrus.FatalLevel: logWriter,
		logrus.DebugLevel: logWriter,
		logrus.WarnLevel:  logWriter,
		logrus.ErrorLevel: logWriter,
		logrus.PanicLevel: logWriter,
	}
	hook := lfshook.NewHook(writerMap, &logrus.TextFormatter{
		TimestampFormat: "2006-01-02 15:04:05",
	})
	logger.AddHook(hook)

	setOutPut(src, true) //true 表示同时输出到控制台,false 表示只输出到文件

	return func(c *gin.Context) {
		start := time.Now()
		c.Next()
		stopTime := time.Since(start).Milliseconds()
		spendTime := fmt.Sprintf("%d ms", stopTime)
		hostname, _ := os.Hostname()
		statusCode := c.Writer.Status()
		clientIp := c.ClientIP()
		method := c.Request.Method
		path := c.Request.RequestURI
		useragent := c.Request.UserAgent()
		dataSize := c.Writer.Size()
		if dataSize < 0 {
			dataSize = 0
		}

		entry := logger.WithFields(logrus.Fields{
			"HostName":   hostname,
			"statusCode": statusCode,
			"SpendTime":  spendTime,
			"Ip":         clientIp,
			"Method":     method,
			"Path":       path,
			"UserAgent":  useragent,
			"DataSize":   dataSize,
			"ReqData":    c.Request.Form,
		})

		if len(c.Errors) > 0 {
			entry.Error(c.Errors.ByType(gin.ErrorTypePrivate).String())
		} else {
			entry.Info()
		}

		if statusCode >= 500 {
			logrus.Error()
		} else if statusCode >= 400 {
			logrus.Warn()
		} else {
			logrus.Info()
		}
	}
}
